package com.huirui.server.handler;

import com.huirui.server.exception.BaseException;
import com.huirui.server.pojo.result.Result;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
@Slf4j
@Hidden
/*
  全局异常处理器
  统一处理应用中抛出的异常，返回标准化的响应结果
 */
public class GlobalExceptionHandler {
    /**
     * 处理自定义业务异常（BaseException）
     * 当业务逻辑中主动抛出BaseException及其子类异常时，会被此方法捕获
     *
     * @param ex 捕获到的BaseException实例，包含业务异常信息
     * @return 统一响应对象Result，封装错误信息
     */
    @ExceptionHandler(BaseException.class)
    public Result<String> BaseExceptionHandler(BaseException ex) {
        // 用warn级别日志记录业务异常（非系统错误，属于预期内的业务场景）
        log.warn("捕获业务异常:{}", ex.getMessage());
        // 获取异常中封装的业务错误消息
        String message = ex.getMessage();
        // 构建错误响应并返回
        return Result.error(message);
    }

    /**
     * 处理参数校验异常（ConstraintViolationException）
     * 当@RequestParam/@PathVariable等简单参数校验失败时（如手机号格式错误），会被此方法捕获
     *
     * @param e 捕获到的参数校验异常实例，包含校验失败信息
     * @return 统一响应对象Result，封装具体的校验错误提示
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<String> handleValidationException(ConstraintViolationException e) {
        // 从异常中获取第一个校验失败的消息（如@Pattern中定义的"手机号格式不正确"）
        // 注：若有多个校验失败，只返回第一个错误信息
        String errorMsg = e.getConstraintViolations().iterator().next().getMessage();
        // 构建错误响应并返回
        return Result.error(errorMsg);
    }

    /**
     * 处理请求参数校验失败的异常（MethodArgumentNotValidException）
     * 当使用@Valid注解验证请求参数时，如果参数不符合校验规则（如@NotNull、@Size等），
     * 会抛出此异常，本方法用于统一捕获并处理这类异常
     *
     * @param e 方法参数校验异常对象，包含了具体的校验失败信息
     * @return 统一的响应结果Result，其中包含错误信息
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 从异常对象中获取绑定结果（BindingResult），包含所有校验失败的字段信息
        // 调用getFieldErrors()获取所有字段校验失败的详情列表
        // getFirst()获取列表中的第一个错误信息（通常只需要显示第一个错误提示给用户）
        // getDefaultMessage()获取该字段校验失败时的自定义提示信息（如@NotBlank(message="xxx")中定义的消息）
        String errorMsg = e.getBindingResult()
                .getFieldErrors()
                .getFirst()  // 获取第一个错误字段信息
                .getDefaultMessage();  // 获取该字段的错误提示

        // 返回错误响应结果，将提取到的错误信息传入
        return Result.error(errorMsg);
    }
}
